home *** CD-ROM | disk | FTP | other *** search
- _MEASURING FRAGMENTATION_
- by James Harrington
-
- [LISTING ONE]
-
- /* This module contains a generic function that calculates a fragmen-
- tation index. This index depends on the numbers of used and free
- block, the largest number of bytes that can currently be allocated
- in a contiguous block, and the total amount of free memory.
-
- Several functions declared as "extern" will be found in other
- modules, where each module calculates values as appropriate for
- a particular memory manager.
- */
-
- #include <stdio.h>
-
- double fragindex( void );
- double getHeapSizeF( void );
- double getBreakupF( void );
- double getLargeFreeF( void );
- double getWorstCase( void );
-
- extern double getWorstCase( void ); /* In manager-specific module */
- extern long getnfreeblks( void ); /* In manager-specific module */
- extern long getnusedblks( void ); /* In manager-specific module */
- extern long getlargest( void ); /* In manager-specific module */
- extern long gettotalfree( void );
-
- /*********************************************************************
- *
- * double fragindex( void )
- *
- * This procedure returns a relative value that reflects the degree of
- * heap fragmentation. It is calculated as follows:
- *
- * frag_index = BreakupFactor / LargeFreeFactor
- *
- * BreakupFactor = number of free blocks-1 / number of used
- * blocks+1, where the free memory above utilized heap is
- * counted as a free block.
- * LargeFreeFactor = size of largest block that can be success-
- * fully allocated / total amount of unused memory,
- * including overhead.
- *
- * maximal fragmentation occurs when every other block is free, all
- * blocks are of the minimal size, and all of memory has been filled
- * with used:free block pairs.
- *
- * If adjacent free blocks are allowed to exist, maximal fragmentation
- * occurs when every block is free (except perhaps for one, and not
- * counting any blocks allocated by startup code), all blocks are of
- * the minimal size, and all of memory has been filled with free
- * blocks.
- *
- * Returns -1 in case of error condition - corrupt heap or setdos()
- * not called in an MSC program. setdos() is required only if compar-
- * ing with other memory managers.
- *
- *********************************************************************/
-
- double fragindex( void )
- {
- double breakupF, largeFreeF;
-
- breakupF = getBreakupF();
- largeFreeF = getLargeFreeF();
-
- if( breakupF<0 || largeFreeF<0 )
- return( -1 );
-
- if( !largeFreeF )
- return( 0 );
- else
- return ( breakupF/largeFreeF );
- }
-
- /*********************************************************************
- *
- * getBreakupF
- *
- * Returns the BreakupFactor for use in the fragindex function.
- *
- *********************************************************************/
-
- double getBreakupF( void )
- {
- long nfree, nused;
-
- nfree = getnfreeblks();
- nused = getnusedblks();
-
- if( nfree<=0 )
- return(nfree);
-
- return (double)(--nfree) / (double)(++nused);
- }
-
- /*********************************************************************
- *
- * getLargeFreeF
- *
- * Returns the LargeFreeFactor for use in the fragindex function.
- *
- * Returns -1 if error in heapwalk, 0 if is no free memory
- *
- *********************************************************************/
-
- double getLargeFreeF( void )
- {
- double sizelargest;
-
- sizelargest = (double)getlargest();
-
- if( sizelargest < 0 )
- return( -1 );
-
- if( !sizelargest )
- return( 0 );
- else
- return (sizelargest / (double)gettotalfree());
- }
-
-
- [LISTING TWO]
-
- /* Provides Borland-specific versions of functions called by fragindex() */
-
- /* Assumes no UMBs, etc., are available to malloc() */
-
- #include <alloc.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- long gettotalfree( void );
- long getnusedblks( void );
- long getnfreeblks( void );
- long getlargest( void );
- void setdos( void );
-
- /*********************************************************************
- *
- * getlargest( void );
- *
- * Returns a number of bytes, the size of the largest block of
- * contiguous free memory that can be successfully allocated from the
- * heap with farmalloc(), malloc(), or _halloc().
- *
- *********************************************************************/
-
- long getlargest( void )
- {
- struct farheapinfo hinfo;
- long size = 0;
-
- hinfo.ptr = NULL;
-
- while( heapwalk( &hinfo ) == _HEAPOK ){
-
- if( !hinfo.in_use )
- size = max( size, hinfo.size );
- }
-
- size = max( size, farcoreleft()-4 );
-
- return( size );
- }
-
- /*********************************************************************
- *
- * getnfreeblks( void );
- *
- * Returns the number of free blocks in the heap. Doesn't count memory
- * above utilized heap.
- *
- * Returns -1 if heap is corrupt
- *
- *********************************************************************/
-
- long getnfreeblks( void )
- {
- struct farheapinfo hinfo;
- register int count = 0;
-
- if( heapcheck() < 0 )
- return( -1 );
-
- hinfo.ptr = NULL;
-
- while( heapwalk( &hinfo ) == _HEAPOK ){
-
- if( !hinfo.in_use )
- count++;
- }
- /* ret count+1 to count coreleft() memory */
- return (long) ++count;
- }
-
- /*********************************************************************
- *
- * getnusedblks( void );
- *
- * Returns the number of allocated blocks in the heap.
- *
- *********************************************************************/
-
- long getnusedblks( void )
- {
- struct farheapinfo hinfo;
- register int count = 0;
-
- hinfo.ptr = NULL;
-
- while( heapwalk( &hinfo ) == _HEAPOK ){
-
- if( hinfo.in_use )
- count++;
- }
-
- return (long) count;
- }
-
- /*********************************************************************
- *
- * gettotalfree( void );
- *
- * Returns the total amount of free memory.
- *
- *********************************************************************/
-
- long gettotalfree( void )
- {
- struct farheapinfo hinfo;
- long size=0;
-
- hinfo.ptr = NULL;
-
- while( heapwalk( &hinfo ) != _HEAPEND ){
-
- if( !hinfo.in_use )
- size+=(hinfo.size+4);
- }
- size += farcoreleft();
-
- return (long)size;
- }
-
-
- /*********************************************************************
- *
- * setdos( void );
- *
- * For sake of compatibility with fragmic.c
- *
- *********************************************************************/
-
- void setdos( void )
- {
- }
-
-
-
- [LISTING THREE]
-
- /* Provides Microsoft C-specific versions of functions used in
- calculating a fragmentation index. */
-
- /* Assumes no UMBs, etc., are available to malloc() */
-
- #include <malloc.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <dos.h>
-
- #define LOWSEGS 100
- /* signed int, must be > 0 */
- /* represents the max number of
- free DOS blocks expected at
- time of program startup */
- #define NDOS 200
- /* signed int, must be > 0 */
- /* affected by value of
- _amblksize variable - smaller
- val means larger NDOS req'd */
- /* represents max number of
- free DOS blocks
- expected */
-
- int nsegs, _callflag;
- unsigned _far dosseg_array[ LOWSEGS ]; /* saves segs for findfrag() */
- unsigned _far seg_array[ NDOS ]; /* saves segs for setdos() */
-
- void limitheap( void );
- void freesegs( void );
- long countdos( void );
- long bigdos( void );
- long dossize( void );
- long gettotalfree( void );
- long getnusedblks( void );
- long getnfreeblks( void );
- long getlargest( void );
- void setdos( void );
- void freedos( int count );
-
- /* Note: _dos_allocmem() is a compiler runtime library function that
- allocates a block of memory directly from MS-DOS through int 21h
- fxn. 48h. You request a number of paragraphs (blocks of 16 bytes).
- Requesting 0xffff paragraphs will result in an error return, with
- the size of the largest allocable block, in paragraphs, being
- returned in the variable whose address is passed as the second
- parameter to _dos_allocmem(). _dos_freemem() frees the blocks
- allocated through _dos_allocmem(), via int 21h fxn 49h.
- */
-
- /*********************************************************************
- *
- * getlargest( void );
- *
- * Returns a number of bytes, the size of the largest block of contigu-
- * ous free memory that can be successfully allocated from the heap
- * with fmalloc(), malloc() (in far data memory models), or _halloc().
- *
- * Returns -1 if error
- *
- *********************************************************************/
-
- long getlargest( void )
- {
- struct _heapinfo hinfo;
- int herr;
- long maxsize = 0;
- long tsize = 0;
- char first = 0;
- unsigned seg = 0;
-
- maxsize = bigdos();
-
- /* Get largest free */
-
- hinfo._pentry = NULL;
-
- while( (herr=_heapwalk( &hinfo )) != _HEAPEND && herr==_HEAPOK){
-
- /* if is a used block... */
- if( hinfo._useflag ){
-
- first = 0;
-
- seg = (unsigned)(((unsigned long)hinfo._pentry)>>16);
- }
-
- /* but if is a free block... */
- else{
-
- /* if last block was a used block */
- if( !first ){
-
- tsize = hinfo._size;
-
- /* If switch DOS blocks */
- if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
- != seg )
- seg =
- (unsigned)(((unsigned long)hinfo._pentry)>>16);
-
- maxsize = max( maxsize, tsize );
-
- first=1;
- }
-
- /* if last block was a free block too */
- else{
-
- /* If switch DOS blocks */
- if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
- != seg ) {
- seg =
- (unsigned)(((unsigned long)hinfo._pentry)>>16);
- tsize = hinfo._size;
- }
- else
- tsize += (hinfo._size+2);
-
- maxsize = max( maxsize, tsize );
- }
- }
- }
-
- return( herr==_HEAPEND?maxsize:-1 );
- }
-
- /*********************************************************************
- *
- * long bigdos( void )
- *
- * Returns the size of the largest block of available DOS memory.
- *
- *********************************************************************/
-
- long bigdos( void )
- {
- unsigned size;
-
- _dos_allocmem( 0xffff, &size );
-
- return( (long)(size-1) * 16L ); /* Size of largest allocable
- block */
- }
-
-
- /*********************************************************************
- *
- * getnfreeblks( void );
- *
- * Returns the number of free blocks in the heap, and assumes adjacent
- * free blocks in the same DOS block can be combined.
- *
- * Returns -1 in case of error
- *
- *********************************************************************/
-
- long getnfreeblks( void )
- {
- struct _heapinfo hinfo;
- int herr;
- unsigned seg;
- long count = 0;
- char first = 0;
-
- /* error if didn't call setdos() */
- if( !_callflag )
- return( -1 );
-
- hinfo._pentry = NULL;
-
- while( (herr=_heapwalk( &hinfo )) != _HEAPEND && herr==_HEAPOK){
-
- /* if is a used block... */
- if( hinfo._useflag ){
-
- first = 0;
-
- seg = (unsigned)(((unsigned long)hinfo._pentry)>>16);
- }
-
- /* but if is a free block... */
- else{
-
- /* if last block was a used block */
- if( !first ){
-
- count++;
-
- /* If switch DOS blocks */
- if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
- != seg )
- seg =
- (unsigned)(((unsigned long)hinfo._pentry)>>16);
- }
-
- /* if last block was a free block too */
- else{
-
- /* If switch DOS blocks */
- if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
- != seg ){
- seg =
- (unsigned)(((unsigned long)hinfo._pentry)>>16);
- count++;
- }
- }
- }
- }
-
- return( herr==_HEAPEND?(count+countdos()):-1 );
- }
-
- /*********************************************************************
- *
- * int countdos( void )
- *
- * Counts the number of free DOS blocks, up to NDOS blocks
- *
- *********************************************************************/
-
- long countdos( void )
- {
- int count;
-
- for( count=0; count<NDOS; count++ ){
-
- _dos_allocmem( 0xffff, &seg_array[count] );
-
- if( seg_array[count] )
- _dos_allocmem( seg_array[count], &seg_array[count] );
- else
- break;
- }
-
- /* count is the number of allocated blocks */
-
- freedos(count);
-
- if( count == NDOS ){
- printf("\nToo many DOS blocks; increase value of NDOS.");
- exit(0);
- }
-
- return count;
- }
-
- /*********************************************************************
- *
- * getnusedblks( void );
- *
- * Returns the number of allocated blocks in the heap.
- *
- *********************************************************************/
-
- long getnusedblks( void )
- {
- struct _heapinfo hinfo;
- long count = 0;
-
- hinfo._pentry = NULL;
-
- while( _heapwalk( &hinfo ) != _HEAPEND ){
-
- if( hinfo._useflag )
- count++;
- }
- return count;
- }
-
- /*********************************************************************
- *
- * gettotalfree( void );
- *
- * Returns the total amount of free memory.
- *
- *********************************************************************/
-
- long gettotalfree( void )
- {
- struct _heapinfo hinfo;
- long size=0;
-
- hinfo._pentry = NULL;
-
- while( _heapwalk( &hinfo ) != _HEAPEND ){
-
- if( !hinfo._useflag )
- size+=(hinfo._size+2);
- }
- return size + dossize();
- }
-
- /*********************************************************************
- *
- * dossize( void )
- *
- * Counts the number of bytes in free DOS blocks, up to NDOS DOS
- * blocks. Includes 16 bytes overhead for each block.
- *
- *********************************************************************/
- long dossize( void )
- {
- unsigned seg_array[NDOS];
- int count;
- long size = 0;
-
- for( count=0; count<NDOS; count++ ){
-
- _dos_allocmem( 0xffff, &seg_array[count] );
-
- if( seg_array[count] ){
- size += ((long)seg_array[count]+1)*16L;
- _dos_allocmem( seg_array[count], &seg_array[count] );
- }
- else
- break;
- }
-
- /* count is the number of allocated blocks */
-
- freedos(count);
-
- if( count == NDOS ){
- printf("\nToo many DOS blocks; increase value of NDOS.");
- exit(0);
- }
-
- return( size );
- }
-
- /*********************************************************************
- *
- * void freedos( int count )
- *
- * Frees segments stored in seg_array[].
- *
- * Parm "count" is number of stored segments.
- *
- *********************************************************************/
-
- void freedos( int count )
- {
- int i;
-
- if( !count )
- return;
-
- for( i=0; i<count; i++ )
- _dos_freemem( seg_array[i] );
- }
-
- /*********************************************************************
- *
- * setdos( void );
- *
- *********************************************************************/
-
- void setdos( void )
- {
- atexit( freesegs );
- limitheap();
- _callflag++;
- }
-
- /*********************************************************************
- *
- * limitheap()
- *
- * This function allocates all the DOS blocks besides the one
- * immediately above the program block. Assumes that the one above the
- * program block is the biggest free DOS block.
- *
- *********************************************************************/
- void limitheap(void)
- {
- /* nsegs = 0 at start */
-
- while( nsegs<LOWSEGS ){
-
- _dos_allocmem( 0xffff, &dosseg_array[nsegs] );
-
- if( dosseg_array[nsegs] ){
- _dos_allocmem( dosseg_array[nsegs],&dosseg_array[nsegs] );
- nsegs++;
- }
- else
- break;
- }
-
- if( nsegs == LOWSEGS ){
-
- _dos_freemem( dosseg_array[0] );
-
- printf("\nToo many free DOS blocks at start; ");
- printf("\nincrease value of of LOWSEGS.");
- exit(0);
- }
-
- if( nsegs )
- _dos_freemem( dosseg_array[0] );
- }
-
- void freesegs(void)
- {
- int i;
-
- if( !_callflag )
- printf("\nerror: didn't call setdos()");
- else{
- if( nsegs>1 ){
-
- for( i=1; i<nsegs; i++ )
- _dos_freemem( dosseg_array[i] );
- }
- }
- }
-